package com.huanling.main.keyconflictdealer;

import cn.hutool.core.collection.ListUtil;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;

import static cn.hutool.core.collection.CollUtil.emptyIfNull;


/**
 * 宽容模式，不会中断
 * 使用拉链法搜索，通过比较用户选择的"对比列"，尽最大可能找到对应元素（如果没有开启对比，则退化为IGNORE) 并记录日志
 *
 * @author guibo.sun
 * @since 25 七月 2021
 */
public class ZipperFindDealer extends AbstractConflictKeyDealer implements LogNeeded {
    private ConflictKeyContext conflictKeyContext;

    @Override
    protected Map<String, Object> getRemappingResult(String key, Map<String, Object> oldValue, Map<String, Object> newValue) {
        return oldValue;
    }

    @Override
    void preDeal(ConflictKeyContext conflictKeyContext, String key, Map<String, Object> oldValue, Map<String, Object> newValue) {
        this.conflictKeyContext = conflictKeyContext;
        /**
         * 如果之前没有这个key的重复数据（即目前的newValue是第二个这个key的数据）将new value和old value 都加入
         * 否则（第三个以及之后）只加入new value
         */
        conflictKeyContext.getConflictKeyItems().computeIfPresent(key, (k, maps) -> {
            maps.add(newValue);
            return maps;
        });
        conflictKeyContext.getConflictKeyItems().putIfAbsent(key, ListUtil.list(false, oldValue, newValue));
    }



    /**
     * 提供根据拉链法搜索的方法
     *
     * @param key          参照列
     * @param anotherValue 查找的具体值
     * @return
     */
    public Optional<Map<String, Object>> bestEffortSearch(String key, Map<String, Object> anotherValue) {
        BiPredicate<Map<String, Object>, Map<String, Object>> valueEqualsJudge = conflictKeyContext.getValueEqualsJudge();
        return emptyIfNull(conflictKeyContext.getConflictKeyItems().get(key)).stream()
                .filter(originValue -> valueEqualsJudge.test(originValue, anotherValue)).findFirst();
    }


    @Override
    public List<Map<String, Object>> getLogDataList() {
        return conflictKeyContext.getConflictKeyItems().values().stream()
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
    }
}
